﻿using AVT.VmbAPINET;
using System;
using System.Runtime.InteropServices;

namespace Camera
{
    /**********参数设置功能空缺**********/
    public class CameraAlliedVision : CameraBase
    {
        private Vimba sys;
        private bool mSystemFlag, mCameraFlag, mStreamingFlag;
        private AVT.VmbAPINET.Camera mCamera;
        private string aCamera;

        public override event ReadImageDelegate ReadImageEvent;
        public override event ConnectLossDelegate ConnectLossEvent;

        public CameraAlliedVision()
        {
            sys = new Vimba();
        }

        public static string[] DeviceListAcq()
        {
            Vimba sys = new Vimba();                // Create a VimbaSystem object. This will be our entry point for everything else
            string[] deviceList;
            try
            {
                sys.Startup();                      // Initialize the Vimba API
                deviceList = new string[sys.Cameras.Count];
                // Query all static details of all known cameras and print them out.
                // We don't have to open the cameras for that.
                for (int i = 0; i < sys.Cameras.Count; ++i)
                {
                    // Check if we can open the camera in full mode
                    //if (VmbAccessModeType.VmbAccessModeFull == cameras[i].PermittedAccess)
                    {
                        // Now get the camera ID
                        deviceList[i] = sys.Cameras[i].Id;
                    }
                }
            }
            finally
            {
                sys.Shutdown();
            }
            return deviceList;
        }

        public override bool Open(string aCamera)
        {
            this.aCamera = aCamera;
            // -start Vimba
            // -open camera in full access mode and get handle
            if (!PrepareCamera(aCamera))
            {
                return false;
            }
            try
            {
                // select FrameStart trigger via TriggerSelector feature
                mCamera.Features["TriggerSelector"].EnumValue = "FrameStart";
            }
            catch (VimbaException)
            {
                FailureShutdown();
                return false;
            }
            try
            {
                // set GVSP packet size to max value (MTU)
                // and wait until command is done
                mCamera.Features["GVSPAdjustPacketSize"].RunCommand();
                // check if operation is done
                bool lFlag = false;
                do
                {
                    lFlag = mCamera.Features["GVSPAdjustPacketSize"].IsCommandDone();
                } while (false == lFlag);
            }
            catch (VimbaException)
            {
                FailureShutdown();
                return false;
            }
            return true;
        }

        /// <summary>
        /// Start Vimba and open camera with given string
        /// </summary>
        /// <param name="aCamera">The ID or IP address of the camera to work with</param>
        private bool PrepareCamera(string aCamera)
        {
            // check parameter
            if (0 == aCamera.Length)
            {
                return false;
            }
            try
            {
                // start Vimba
                sys.Startup();
            }
            catch (VimbaException)
            {
                return false;
            }
            mSystemFlag = true;
            try
            {
                // open camera with given string (could be device ID or IP address)
                mCamera = sys.OpenCameraByID(aCamera, VmbAccessModeType.VmbAccessModeFull);
            }
            catch (VimbaException)
            {
                FailureShutdown();
                return false;
            }
            mCameraFlag = true;
            return true;
        }

        /// <summary>
        /// Called when any failure occurs whithin the example.
        /// Ensures to stop streaming, close interface, close camera and shutdown Vimba.
        /// </summary>
        private void FailureShutdown()
        {
            if (mStreamingFlag)
            {
                try
                {
                    // stop streaming
                    mCamera.StopContinuousImageAcquisition();
                }
                catch (VimbaException)
                {

                }
            }
            if (mCameraFlag)
            {
                try
                {
                    // close camera
                    mCamera.Close();
                }
                catch (VimbaException)
                {

                }
            }
            if (mSystemFlag)
            {
                try
                {
                    // shutdown Vimba
                    sys.Shutdown();
                }
                catch (VimbaException)
                {

                }
            }
        }

        public override bool Close()
        {
            // stop streaming
            if (!StopStreaming())
            {
                return false;
            }
            // -close camera
            // -shutdown Vimba
            if (!StopCamera())
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// Stop camera acquisition
        /// </summary>
        private bool StopStreaming()
        {
            try
            {
                // unregister frame callback
                mCamera.OnFrameReceived -= FrameReceived;
            }
            catch (VimbaException)
            {
                FailureShutdown();
                return false;
            }
            try
            {
                // stop continuous image acquisition
                mCamera.StopContinuousImageAcquisition();
            }
            catch (VimbaException)
            {
                FailureShutdown();
                return false;
            }
            mStreamingFlag = false;
            return true;
        }

        /// <summary>
        /// Close camera and shutdown Vimba
        /// </summary>
        private bool StopCamera()
        {
            try
            {
                // close camera
                mCamera.Close();
            }
            catch (VimbaException)
            {
                FailureShutdown();
                return false;
            }
            mCameraFlag = false;
            try
            {
                // shutdown Vimba
                sys.Shutdown();
            }
            catch (VimbaException)
            {
                return false;
            }
            mSystemFlag = false;
            return true;
        }

        public override bool StartGrab()
        {
            // -adjust GVSP packet size
            // -get payload size
            // -allocate memory for frame buffers
            // -announce frames and move them to buffer input pool
            // -start capture engine
            // -move frames to capture queue (buffer output queue)
            // -call start acquisition feature in the camera
            if (!PrepareStreaming())
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// Prepare camera acquisition
        /// </summary>
        private bool PrepareStreaming()
        {
            try
            {
                // register frame callback
                mCamera.OnFrameReceived += FrameReceived;
            }
            catch (VimbaException)
            {
                FailureShutdown();
                return false;
            }
            try
            {
                // start continuous image acquisition
                mCamera.StartContinuousImageAcquisition(3);
            }
            catch (VimbaException)
            {
                FailureShutdown();
                return false;
            }
            mStreamingFlag = true;
            return true;
        }

        /// <summary>
        /// Frame callback
        /// </summary>
        private void FrameReceived(Frame aFrame)
        {
            try
            {
                // Convert frame into displayable image
                //相机像素数据
                byte[] buffer = aFrame.Buffer;
                //锁定像素数据
                GCHandle hand = GCHandle.Alloc(buffer, GCHandleType.Pinned);
                //获取像素数据的指针
                IntPtr pr = hand.AddrOfPinnedObject();
                //转成灰度图HObject
                //HOperatorSet.GenImage1(out HObject image1, new HTuple("byte"), aFrame.Width, aFrame.Height, pr);
                //释放内存
                if (hand.IsAllocated)
                {
                    hand.Free();
                }
                Imgdata imgdata = new Imgdata
                {
                    data = pr,
                    width = (int)aFrame.Width,
                    height = (int)aFrame.Height
                };
                ReadImageEvent(imgdata);
            }
            finally
            {
                try
                {
                    // re-queue frame
                    mCamera.QueueFrame(aFrame);
                }
                catch (VimbaException)
                {
                    FailureShutdown();
                }
            }
            /* 主动调用回收垃圾 */
            GC.Collect();
        }

        public override void StopGrab()
        {
            // stop streaming
            StopStreaming();
        }

        public override void SetTriggerMode(TriggerMode triggerMode)
        {
            try
            {
                // enable trigger
                mCamera.Features["TriggerMode"].EnumValue = triggerMode.ToString();
            }
            catch (VimbaException)
            {
                FailureShutdown();
            }
        }

        public override void SetTriggerSource(TriggerSource triggerSource)
        {
            if (mCamera == null)
            {
                return;
            }
            string source;
            switch (triggerSource)
            {
                case TriggerSource.Freerun:
                case TriggerSource.Line1:
                case TriggerSource.Software:
                    source = triggerSource.ToString();
                    break;
                default:
                    return;
            }
            try
            {
                // set trigger source to Action0
                mCamera.Features["TriggerSource"].EnumValue = source;
            }
            catch (VimbaException)
            {
                FailureShutdown();
            }
        }

        public override bool TriggerSoftware()
        {
            if (null != mCamera)
            {
                mCamera.Features["TriggerSoftware"].RunCommand();
            }
            return true;
        }

        public override string GetSerialNumber()
        {
            return aCamera;
        }

        public override double GetParameter(string key)
        {
            //return mCamera.Features[key].FloatValue;
            return 0;
        }

        public override void SetParameter(string key, double floatValue)
        {
            //mCamera.Features[key].FloatValue = floatValue;
        }

        public override void UserSave()
        {
            //mCamera.Features["UserSetSelector"].IntValue = 1;
            //mCamera.Features["UserSetSave"].RunCommand();
        }

        public override void LoadConfigurationFromFile(string fileName)
        {

        }
    }
}
